package com.ocom.mqsimple.business.ordermeal;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ocom.common.entity.card.EntityXfGoodListDishes;
import com.ocom.common.entity.card.EntityXfMealInfo;
import com.ocom.common.entity.master.EntityFileDownloadInfo;
import com.ocom.common.request.payconfig.mealorder.GetOrderDishesRequest;
import com.ocom.common.request.web.ConsumeDetailRequest;
import com.ocom.common.resp.Result;
import com.ocom.common.utils.DateUtil;
import com.ocom.common.utils.RandomUtil;
import com.ocom.common.utils.csv.ZipUtil;
import com.ocom.common.vo.payconfig.kitchenprinter.PlanKitchenPrinterRequest;
import com.ocom.common.vo.webapi.PageVO;
import com.ocom.mqsimple.config.OrderMealConfig;
import com.ocom.mqsimple.feign.AccessClientService;
import com.ocom.mqsimple.feign.MinioClientService;
import com.ocom.mqsimple.feign.PayConfigClientService;
import com.ocom.mqsimple.feign.XfRecordFeign;
import com.ocom.redis.util.RedisUtil;
import com.rabbitmq.client.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;


@Component
public class OrderMealExportConsumerMqListener {

    private Logger logger = LoggerFactory.getLogger(OrderMealExportConsumerMqListener.class);

    @Value("${save.path}")
    String excelPath;

    @Resource
    RedisUtil redisUtil;

    @Autowired
    private PayConfigClientService payConfigClientService;

    @Autowired
    AccessClientService accessClientService;

    @Autowired
    private XfRecordFeign xfRecordFeign;

    @Autowired
    MinioClientService minioClientService;

    /**
     * 把该监听命名为A监听
     * 监听队列  远程服务支付接口发送消息  该队列会接受
     * [message, headers, channel]
     *
     * @return {@link }
     * @throws
     */
    @RabbitListener(queues = OrderMealConfig.ORDER_MEAL_QUEUE)
    public void process(Message message, @Headers Map<String, Object> headers, Channel channel) throws Exception {
        String humanMessage = new String(message.getBody(), StandardCharsets.UTF_8);
        //TODO 数据库操作样例

        Object requestRedis = redisUtil.get(humanMessage);

        if (requestRedis == null) {
            logger.info("orderMealExport-error:redis为空异常");
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }

        GetOrderDishesRequest request = JSON.parseObject(JSON.toJSONString(requestRedis), GetOrderDishesRequest.class);

        logger.info("orderMealExport 消费中 request【{}】 ", request);


        EntityFileDownloadInfo entityFileDownloadInfo = new EntityFileDownloadInfo();
        entityFileDownloadInfo.setId(request.getId().longValue());


        String randStr = RandomUtil.getRandomString(32);


        // 设置表格头
        Object[] head = {"订单号","人员姓名","人员编号","消费时间","就餐日期","餐段名称"
        ,"菜品名称","菜品数量","菜品价格","送餐地址","备注","订单状态"};
        List<Object> headList = Arrays.asList(head);


        // 设置数据
        request.setPage(1);
        request.setSize(1);
        Result<PageVO<EntityXfGoodListDishes>> result = xfRecordFeign.getOrderDishesC(request);

        if (result.getCode() != 200) {

            logger.info("OrderMealExport-error: 【{}】", request);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            if(request.getType()==1) {
                //下载失败
                entityFileDownloadInfo.setStatus(2l);
                entityFileDownloadInfo.setRemark("获取记录 - 获取异常");
                accessClientService.UpdateFileStatus(entityFileDownloadInfo);
            }
            return;
        }

        //下载失败 无数据
        if (result.getData().getTotal() == null || result.getData().getTotal() <= 0) {
            if(request.getType()==1) {
                //下载失败
                entityFileDownloadInfo.setStatus(2l);
                entityFileDownloadInfo.setRemark("无有效记录");
                accessClientService.UpdateFileStatus(entityFileDownloadInfo);
            }
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }

        int listCount = result.getData().getTotal();
        //导出6万以上数据。。。
        int pageSize = 100000;//设置每一个excel文件导出的数量   500的倍数  1次请求500条
        int quotient = listCount / pageSize + (listCount % pageSize > 0 ? 1 : 0);//循环次数
        List<File> srcfile = new ArrayList<File>();
        int oneFilePages = pageSize / 500;
        String downloadFilePath = excelPath + randStr + File.separator;

        try {

            Result mealNameInfo = payConfigClientService.GetMealNameInfo(request.getComId());
            Map<String,String> mealNameMap = new HashMap<>();
            if (200 == mealNameInfo.getCode()) {
                Map<String, Object> mealNameInfoData = JSON.parseObject(JSON.toJSONString(mealNameInfo.getData()), HashMap.class);
                List<EntityXfMealInfo> entityXfMealInfos = JSON.parseArray(JSON.toJSONString(mealNameInfoData.get("list")), EntityXfMealInfo.class);
                mealNameMap = entityXfMealInfos.stream().collect(Collectors.toMap(e -> e.getMealNo(),
                        e -> e.getMealName(),
                        (e1, e2) -> e1));
            }

            for (int i = 0; i < quotient; i++) {
                int startPage = oneFilePages * i + 1;
                int endPage = oneFilePages + startPage - 1;

                if (listCount % pageSize > 0 && (i + 1) == quotient) {
                    int lastTotal = listCount - pageSize * (i);
                    if (lastTotal <= 500) {
                        endPage = startPage;
                    } else {
                        endPage = startPage + lastTotal / 500;
                    }
                }


                // 导出文件名称
                String fileName = String.valueOf(i);
                // 导出CSV文件
                File csvFile = createCSVFile(headList, downloadFilePath, fileName, request, startPage, endPage,mealNameMap);
                srcfile.add(csvFile);
            }
            if(request.getType()==1) {
                ZipUtil.zipFiles(srcfile, new File(excelPath + randStr + "download.zip"));
            }
        } catch (Exception e) {
            //下载失败
            logger.info("【ConsumeDetailExport】-error: 【{}】", e);
            if(request.getType()==1) {
                entityFileDownloadInfo.setStatus(2l);
                entityFileDownloadInfo.setRemark("导出异常");
                accessClientService.UpdateFileStatus(entityFileDownloadInfo);
            }
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        } finally {
            try {
                ZipUtil.dropFolderOrFile(new File(downloadFilePath));
            } catch (Exception e) {
                logger.error("点餐查询mq异常 【{}】",e);
            }
        }

        if(request.getType()!=1) {
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }

        File file1 = null;
        try {
            file1 = new File(excelPath + randStr + "download.zip");
            Result result3 = minioClientService.upload(file1);
            if (result3.getCode() != 200) {
                //更改状态 失败
                entityFileDownloadInfo.setStatus(2l);
                accessClientService.UpdateFileStatus(entityFileDownloadInfo);
            } else {
                JSONObject jsonObject1 = JSON.parseObject(JSON.toJSONString(result3.getData()));
                entityFileDownloadInfo.setStatus(1l);
                entityFileDownloadInfo.setUrl(jsonObject1.getString("imageUrl"));
                logger.info("entityFileDownloadInfo 【{}】", entityFileDownloadInfo);
                accessClientService.UpdateFileStatus(entityFileDownloadInfo);
            }
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            logger.info("OrderMealExport-end:【{}】", humanMessage);
        } catch (Exception e) {
            logger.error("OrderMealExport 人员导出IO异常 【{}】", e);
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);//继续消费该消息
        } finally {
            try {
                file1.delete();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }


    }



    /**
     * 把该监听命名为B监听
     * 监听死信队列  远程服务支付接口发送消息  该队列会接受
     * [message, headers, channel]
     *
     * @return {@link }
     * @throws
     */
    @RabbitListener(queues = OrderMealConfig.ORDER_MEAL_DIE_QUEUE)
    public void processForDie(Message message, @Headers Map<String, Object> headers, Channel channel) throws Exception {
        //死信队列放弃
        logger.info("点餐明细导出-死信队列放弃 ， 【{}】", message);
        String humanMessage = new String(message.getBody(), StandardCharsets.UTF_8);
        Object requestRedis = redisUtil.get(humanMessage);
        redisUtil.dels(humanMessage);

        if (requestRedis == null) {
            logger.info("OrderMealExport-processForDie:redis为空异常");
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }

        ConsumeDetailRequest request = JSON.parseObject(JSON.toJSONString(requestRedis), ConsumeDetailRequest.class);

        EntityFileDownloadInfo entityFileDownloadInfo = new EntityFileDownloadInfo();
        entityFileDownloadInfo.setId(request.getId().longValue());

        //获取异常-跳过  失败处理

        //下载失败
        entityFileDownloadInfo.setStatus(2l);
        entityFileDownloadInfo.setRemark("死信队列-导出失败");
        accessClientService.UpdateFileStatus(entityFileDownloadInfo);

        channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
    }


    /**
     * CSV文件列分隔符
     */
    private static final String CSV_COLUMN_SEPARATOR = ",";

    /**
     * CSV文件列分隔符
     */
    private static final String CSV_RN = "\r\n";

    /**
     * CSV文件生成方法
     *
     * @param head
     * @param outPutPath
     * @param filename
     * @return
     */
    public File createCSVFile(List<Object> head, String outPutPath, String filename, GetOrderDishesRequest request, int startPage, int endPage,Map<String,String> mealNameMap) throws Exception {


        File csvFile = null;
        BufferedWriter csvWtriter = null;
        try {
            if(request.getType()==1) {
                csvFile = new File(outPutPath + File.separator + filename + ".csv");
                File parent = csvFile.getParentFile();
                if (parent != null && !parent.exists()) {
                    parent.mkdirs();
                }
                csvFile.createNewFile();

                // GB2312使正确读取分隔符","
                csvWtriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(csvFile), "UTF-8"), 1024);
                // 写入文件头部
                writeRow(head, csvWtriter, null);
            }

            // 写入文件内容
//            for (List<Object> row : dataList) {
//                writeRow(row, csvWtriter);
//            }

            for (int i = startPage; i <= endPage; i++) {
                request.setPage(i);
                request.setSize(500);
                Result<PageVO<EntityXfGoodListDishes>> result1 = xfRecordFeign.getOrderDishesC(request);
                if (result1.getCode() != 200 || result1.getData() == null) {
                    throw new Exception("查询异常 返回："+result1);
                }
                if (result1.getData() != null && result1.getData().getRecords() != null && result1.getData().getRecords().size() > 0) {
                    for (EntityXfGoodListDishes entityXfGoodListDishes : result1.getData().getRecords()) {

                        if(request.getType()==2){

                            if (entityXfGoodListDishes.getIfRefund()>0) {
                                continue;
                            }

                            PlanKitchenPrinterRequest planKitchenPrinterRequest=new PlanKitchenPrinterRequest();
                            planKitchenPrinterRequest.setComId(request.getComId());
                            planKitchenPrinterRequest.setOrderNo(entityXfGoodListDishes.getOrderNo());
                            planKitchenPrinterRequest.setMonthValue(entityXfGoodListDishes.getMonthValue());
                            planKitchenPrinterRequest.setPointId(entityXfGoodListDishes.getPointId().longValue());
                            planKitchenPrinterRequest.setForcePrint(true);
                            planKitchenPrinterRequest.setCheckPrint(false);
                            payConfigClientService.planKitchenPrinter(planKitchenPrinterRequest);
                            continue;
                        }

                        //金额是否特殊处理的配置
                        Map<Integer,Boolean> booleanMap =new HashMap<>();
                        booleanMap.put(7,true);
                        booleanMap.put(8,true);

                        List<Object> row = new ArrayList<>();
                        row.add(entityXfGoodListDishes.getOrderNo());
                        row.add(entityXfGoodListDishes.getPName());
                        row.add(entityXfGoodListDishes.getPCode());
                        row.add(DateUtil.getDateTime(entityXfGoodListDishes.getConsTime()));
                        row.add(DateUtil.getDateTime(entityXfGoodListDishes.getMealDate()));
                        if (mealNameMap.containsKey(entityXfGoodListDishes.getMealNo().toString())) {
                            row.add(mealNameMap.get(entityXfGoodListDishes.getMealNo().toString()));
                        } else {
                            row.add("");
                        }
                        row.add(entityXfGoodListDishes.getDishesName());
                        row.add(entityXfGoodListDishes.getWeightNumber());
                        row.add((double)entityXfGoodListDishes.getDishesPrice()/100);
                        row.add(entityXfGoodListDishes.getReceiptName());
                        row.add(entityXfGoodListDishes.getRemark());
                        if(entityXfGoodListDishes.getIfRefund()==0){
                            row.add("未退款");
                        }else{
                            row.add("已退款");
                        }
                        writeRow(row, csvWtriter,booleanMap);
                    }
                }
            }
            if(csvWtriter!=null) csvWtriter.flush();
        } catch (Exception e) {
            logger.error("【OrderMealExport】 【异常】 【{}】",e);
            throw new Exception("查询异常");
        } finally {
            try {
                if(csvWtriter!=null)csvWtriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return csvFile;
    }

    /**
     * 写一行数据方法
     *
     * @param row
     * @param csvWriter
     * @param  booleanMap 是否数字 不加字符号
     * @throws IOException
     */
    private void writeRow(List<Object> row, BufferedWriter csvWriter, Map<Integer,Boolean> booleanMap) throws IOException {
        // 写入文件头部

        for (int m = 0; m < row.size(); m++) {
            Object data = row.get(m);
            StringBuffer buf = new StringBuffer();
 //           String  rowStr = buf.append(data).append(",").toString();
            String rowStr = null;
            if(booleanMap!=null &&  booleanMap.containsKey(m) && booleanMap.get(m)==true){
                rowStr = buf.append(data).append(",").toString();
            }else{
                rowStr =  buf.append("\"").append(data).append("\t\",").toString();
            }
            csvWriter.write(rowStr);
        }
        csvWriter.newLine();
    }

}
